home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / man.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  18KB  |  733 lines

  1. /* man - display and manage manual pages    Author: Dick van Veen */
  2.  
  3. /* Options:
  4.  *    man <ar-dir>? <ar-name>? <man-page>+
  5.  *        display <man-page> from <ar-name> in <ar-dir>.
  6.  *    man <ar-dir>? <ar-name>?
  7.  *        display contents of <ar-name> in <ar-dir>,
  8.  *        by using the <cursor-keys> and <return> a page is choosen.
  9.  *
  10.  * <ar-dir>    is a directory name starting with a '/'.
  11.  *        the default directory is '/usr/man'.
  12.  *
  13.  * <ar-name>    is a digit, when no digit is used, chapter 1 searched.
  14.  */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <termcap.h>
  22. #include <stdio.h>
  23.  
  24. #ifndef INDEX_H
  25. #define INDEX_H
  26.  
  27. #define MAN_DELIM    '#'
  28. #define NAME_SIZE    12    /* for size in index file */
  29. #define NAME_WIDTH    15    /* for on screen projection */
  30. #define AR_NAME_SIZE    64    /* for file names */
  31. #define AR_DIR        "/usr/man"
  32. #define AR_NAME        "/man"
  33. #define AR_INDEX    "/._man"
  34.  
  35. struct INDEX {
  36.   long page_pos;        /* position in index file */
  37.   char page_name[NAME_SIZE];    /* name of manual page */
  38. };
  39.  
  40. extern char ar_name[AR_NAME_SIZE];    /* name of man archive file */
  41. extern char ar_index[AR_NAME_SIZE];    /* name of index file */
  42. extern struct INDEX *index_buf;    /* contains indices */
  43. extern int max_index_nr;    /* number of indices in index_buf */
  44.  
  45. /* Should be a prototype */
  46. extern void read_index();
  47. #endif
  48. #ifndef DISPLAY_H
  49. #define DISPLAY_H
  50.  
  51. #define MAX_X        (CO/NAME_WIDTH)    /* define width of screen */
  52. #define MAX_Y        (LI)    /* define hight of screen */
  53.  
  54. #define STOP        256    /* codes returned by get_token */
  55. #define READY        257
  56. #define    CURSLEFT    258
  57. #define CURSRIGHT    259
  58. #define CURSUP          260
  59. #define CURSDOWN    261
  60. #define CURSHOME    262
  61. #define CURSEND        263
  62. #define CURSPAGEUP    264
  63. #define CURSPAGEDOWN    265
  64. #define CURSMIDDLE    266
  65.  
  66. extern int term_dialog;        /* do we have a terminal ? */
  67. extern int term_clear;        /* do we clear at exit ? */
  68. extern int top_y, cur_x, cur_y;    /* current position on the screen */
  69. extern char *CL, *CM, *DL, *SO, *SE;    /* for termcap */
  70. extern int CO, LI;        /* for termcap */
  71.  
  72. #define    GOTOXY(x, y)        fputs(tgoto(CM, (x), (y)), stdout)
  73. #define reverse(on)        fputs((on)?SO:SE, stdout)
  74. #define clrscr()        fputs(CL, stdout)
  75.  
  76. /* Should be prototypes */
  77. extern void display();
  78. extern int gettoken();
  79. extern void set_cursor();
  80. extern void term_init();
  81. extern void term_exit();
  82. #endif
  83.  
  84. /* Arguments for do_wait() */
  85. #define    WAIT1        "press <return> to go back to menu"
  86. #define WAIT2        "press <return> for "
  87. #define WAIT3        "press <return> for more ..."
  88.  
  89. #define DO_REVERSE    0x01    /* modes for do_wait() */
  90. #define DO_DELETE    0x02
  91.  
  92. extern char *malloc();
  93. extern char *getenv();
  94.  
  95. /* Forward declaration: */
  96. extern void Exit();
  97. static void man();
  98. static void _man();
  99. static void choose();
  100. static int do_choose();
  101. static int do_wait();
  102.  
  103. main(argc, argv)
  104. int argc;
  105. char **argv;
  106. {
  107.   FILE *man_fd;
  108.  
  109.   argv++;
  110.   argc--;
  111.   if (*argv != NULL && **argv == '/') {
  112.     (void) strcpy(ar_name, *argv);    /* get archive directory */
  113.     (void) strcpy(ar_index, *argv);    /* get index directory */
  114.     argv++;
  115.     argc--;
  116.   } else {
  117.     (void) strcpy(ar_name, AR_DIR);    /* use default directory */
  118.     (void) strcpy(ar_index, AR_DIR);
  119.   }
  120.  
  121.   (void) strcat(ar_name, AR_NAME);    /* get archive name */
  122.   (void) strcat(ar_index, AR_INDEX);    /* get index name */
  123.  
  124.   if (*argv != NULL && isdigit(**argv)) {
  125.     (void) strcat(ar_name, *argv);    /* get archive name */
  126.     (void) strcat(ar_index, *argv);
  127.     argv++;
  128.     argc--;
  129.   } else {
  130.     (void) strcat(ar_name, "1");    /* default archive */
  131.     (void) strcat(ar_index, "1");
  132.   }
  133.   man_fd = fopen(ar_name, "r");    /* open man archive */
  134.   if (man_fd == NULL) {
  135.     fprintf(stderr, "can't open %s\n", ar_name);
  136.     Exit(1);
  137.   }
  138.   read_index();
  139.   term_dialog = isatty(0) && isatty(1);
  140.   term_init();
  141.   if (*argv == NULL)
  142.     choose(man_fd);
  143.   else
  144.     man(man_fd, argv);
  145.   Exit(0);
  146. }
  147.  
  148. void Exit(code)
  149. int code;
  150. {
  151.   term_exit();            /* return terminal to old status */
  152.   exit(code);
  153. }
  154.  
  155. static void man(man_fd, man_pages)
  156. FILE *man_fd;
  157. char **man_pages;
  158. {                /* copy all requested manual pages to
  159.              * standard output */
  160.   int ch;
  161.  
  162.   while (1) {
  163.     _man(man_fd, *man_pages);
  164.     man_pages++;
  165.     if (*man_pages == NULL) break;
  166.     if (term_dialog) {    /* wait before starting next page */
  167.         fputs(WAIT2, stdout);
  168.         if (do_wait(*man_pages, 0)) break;
  169.         fputc('\n', stdout);
  170.     }
  171.   }
  172. }
  173.  
  174. static void _man(man_fd, man_page)
  175. FILE *man_fd;
  176. char *man_page;
  177. {                /* copy the manual page to standard output */
  178.   int index_nr, ch, line_nr = -1;
  179.  
  180.   /* Search entries for man_page */
  181.   for (index_nr = 0; index_nr < max_index_nr; index_nr++) {
  182.     if (strncmp(man_page, index_buf[index_nr].page_name,
  183.             NAME_SIZE) == 0)
  184.         break;
  185.   }
  186.   if (index_nr == max_index_nr) {
  187.     fprintf(stderr, "manual page for %s not available\n", man_page);
  188.     return;
  189.   }
  190.   if (fseek(man_fd, index_buf[index_nr].page_pos, 0) == -1) {
  191.     fprintf(stderr, "can't seek in manaul archive\n");
  192.     Exit(1);
  193.   }
  194.   while ((ch = fgetc(man_fd)) != '\n') {    /* skip names on first line */
  195.     if (ch == EOF) break;
  196.   }
  197.   ch = fgetc(man_fd);        /* display manual page */
  198.   while (ch != EOF) {
  199.     fputc(ch, stdout);
  200.     if (ch == '\n') {
  201.         ch = fgetc(man_fd);
  202.         if (ch == MAN_DELIM) break;
  203.         if (term_dialog) {    /* wait after page full */
  204.             line_nr++;
  205.             if (line_nr != LI - 2) continue;
  206.             if (do_wait(WAIT3, DO_REVERSE | DO_DELETE)) break;
  207.             line_nr = 0;
  208.         }
  209.     } else
  210.         ch = fgetc(man_fd);
  211.   }
  212. }
  213.  
  214. static void choose(man_fd)
  215. FILE *man_fd;
  216. {                /* driver one time chosing a page on the
  217.              * screen */
  218.   int ch, index, max_x, max_y;
  219.  
  220.   if (!term_dialog) {
  221.     fprintf(stderr, "sorry, no terminal\n");
  222.     Exit(1);
  223.   }
  224.   term_clear = 1;
  225.   max_y = (max_index_nr - 1) / MAX_X;    /* determine screen sizes */
  226.   max_x = max_index_nr % MAX_X;
  227.   if (max_x == 0) max_x = MAX_X;
  228.   while (1) {
  229.     index = do_choose(max_x, max_y);
  230.     if (index == STOP) break;
  231.     clrscr();
  232.     _man(man_fd, index_buf[index].page_name, 1);
  233.     (void) do_wait(WAIT1, DO_REVERSE);
  234.   };
  235. }
  236.  
  237. static int do_choose(max_x, max_y)
  238. int max_x, max_y;
  239. {                /* implements the cursor movement on screen,
  240.              * returns entry number */
  241.   int token;
  242.  
  243.   display(1);
  244.   set_cursor(1);
  245.   while (1) {
  246.     fflush(stdout);
  247.     token = gettoken();
  248.     if (token == READY || token == STOP) break;
  249.     set_cursor(0);
  250.     switch (token) {
  251.         case CURSLEFT:
  252.         if (cur_x > 0) cur_x--;
  253.         break;
  254.         case CURSRIGHT:
  255.         if (cur_x < MAX_X - 1) cur_x++;
  256.         break;
  257.         case CURSUP:
  258.         if (cur_y > top_y)
  259.             cur_y--;
  260.         else if (top_y > 0) {
  261.             cur_y--;
  262.             top_y--;
  263.         }
  264.         break;
  265.         case CURSDOWN:
  266.         if (cur_y < (top_y + MAX_Y - 1)) {
  267.             cur_y++;
  268.             if (cur_y > max_y) cur_y = max_y;
  269.         } else if ((top_y + MAX_Y - 1) < max_y) {
  270.             top_y++;
  271.             cur_y++;
  272.         }
  273.         break;
  274.         case CURSPAGEUP:
  275.         top_y -= MAX_Y;
  276.         if (top_y < 0) {
  277.             top_y = 0;
  278.         }
  279.         cur_y = top_y;
  280.         cur_x = 0;
  281.         break;
  282.         case CURSPAGEDOWN:
  283.         top_y += MAX_Y;
  284.         if ((top_y + MAX_Y - 1) >= max_y) {
  285.             top_y = max_y - (MAX_Y - 1);
  286.             if (top_y < 0) top_y = 0;
  287.         }
  288.         cur_y = top_y;
  289.         cur_x = 0;
  290.         break;
  291.         case CURSHOME:
  292.         top_y = 0;
  293.         cur_y = 0;
  294.         cur_x = 0;
  295.         break;
  296.         case CURSEND:
  297.         top_y = max_y - (MAX_Y - 1);
  298.         if (top_y < 0) top_y = 0;
  299.         cur_y = max_y;
  300.         cur_x = 0;
  301.         break;
  302.         case CURSMIDDLE:
  303.         clrscr();    /* redraw screen */
  304.         break;
  305.     }
  306.     if (cur_y == max_y && cur_x >= max_x) cur_x = max_x - 1;
  307.     display(token == CURSMIDDLE);
  308.     set_cursor(1);
  309.   }
  310.   if (token == STOP)
  311.     return(STOP);
  312.   else
  313.     return(cur_x + cur_y * MAX_X);
  314. }
  315.  
  316. static int do_wait(message, mode)
  317. char *message;
  318. int mode;
  319. {                /* print message and waits for a newline,
  320.              * only on terminal dialog */
  321.   int ch;
  322.  
  323.   if (!term_dialog) return(0);
  324.   if (mode & DO_REVERSE) reverse(1);
  325.   fputs(message, stdout);
  326.   if (mode & DO_REVERSE) reverse(0);
  327.   fflush(stdout);
  328.   do {
  329.     ch = getchar();
  330.   } while (ch != EOF && ch != 'q' && ch != 'Q' && ch != '\n');
  331.  
  332.   if ((mode & DO_DELETE) && DL) fprintf(stdout, "%s\r", DL);
  333.   if (ch == '\n') return (0);    /* normal end */
  334.   return(1);            /* abnormal end */
  335. }
  336.  
  337. /* Index.c:    a file to handle the index file */
  338. /*
  339. #include <stdio.h>
  340. #include <sys/types.h>
  341. #include <sys/stat.h>
  342. #include <string.h>
  343. #include <ctype.h>
  344. #include "index.h"
  345. */
  346.  
  347. #define MAN_FGETC(ch, man_fd)    {ch=fgetc(man_fd);man_pos++;}
  348. #define INDEX_SIZE()    (max_index_nr * sizeof(struct INDEX))
  349.  
  350. char ar_name[AR_NAME_SIZE];    /* name of man archiv